#include "../inc/xTimer.h"
#include "../inc/xNet.h"

//#include <winsock.h>
/*
#if !defined(USE_IPX) || defined(TORQUE_COMPILER_MINGW)
#  define NO_IPX_SUPPORT
#endif

#if !defined(NO_IPX_SUPPORT)
#  include <wsipx.h>
#else
typedef void* SOCKADDR_IPX;
#endif


struct NameLookup
{
	U8 hostEntStruct[MAXGETHOSTSTRUCT];
	HANDLE lookupHandle;
	SOCKET socket;
	U16 port;
	NameLookup *nextLookup;
};

static NameLookup *lookupList = NULL;

static Net::Error getLastError();
static TInt defaultPort = 28000;
static TInt netPort = 0;
static SOCKET ipxSocket = INVALID_SOCKET;
static SOCKET udpSocket = INVALID_SOCKET;

enum WinNetConstants {
	MaxConnections = 1024,  ///< Maximum allowed number of connections.
};

HWND winsockWindow = NULL;

static LRESULT PASCAL WinsockProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	U32 error;
	U32 bufLen;
	U32 event;
	SOCKET socket;
	Net::Error err;
	S32 bytesRead;

	static ConnectedNotifyEvent notifyEvent;
	static ConnectedReceiveEvent receiveEvent;
	static ConnectedAcceptEvent acceptEvent;

	switch(message)
	{
	case WM_USER:
		error = WSAGETSELECTERROR(lParam);
		event = WSAGETSELECTEVENT(lParam);
		socket = wParam;
		switch(event)
		{
		case FD_READ:
			err = Net::recv(socket, receiveEvent.data, MaxPacketDataSize, &bytesRead);
			if(err == Net::NoError && bytesRead != 0)
			{
				receiveEvent.tag = socket;
				receiveEvent.size = ConnectedReceiveEventHeaderSize + bytesRead;
				Game->postEvent(receiveEvent);
			}
			break;
		case FD_CONNECT:
			notifyEvent.tag = socket;
			if(error)
				notifyEvent.state = ConnectedNotifyEvent::ConnectFailed;
			else
				notifyEvent.state = ConnectedNotifyEvent::Connected;
			Game->postEvent(notifyEvent);
			break;
		case FD_CLOSE:
			// see first if there is anything to read:
			for(;;)
			{
				err = Net::recv(socket, receiveEvent.data, MaxPacketDataSize, &bytesRead);
				if(err != Net::NoError || bytesRead == 0)
					break;

				receiveEvent.tag = socket;
				receiveEvent.size = ConnectedReceiveEventHeaderSize + bytesRead;
				Game->postEvent(receiveEvent);
			}
			notifyEvent.tag = socket;
			notifyEvent.state = ConnectedNotifyEvent::Disconnected;
			Game->postEvent(notifyEvent);
			break;
		case FD_ACCEPT:
			acceptEvent.portTag = socket;
			acceptEvent.connectionTag = Net::accept(socket, &acceptEvent.address);
			if(acceptEvent.connectionTag != InvalidSocket)
			{
				Net::setBlocking(acceptEvent.connectionTag, false);
				WSAAsyncSelect(acceptEvent.connectionTag, winsockWindow, WM_USER, FD_READ | FD_CONNECT | FD_CLOSE);
				Game->postEvent(acceptEvent);
			}
			break;
		}
		break;
	case WM_USER + 1:
		error = WSAGETASYNCERROR(lParam);
		bufLen = WSAGETASYNCBUFLEN(lParam);
		HANDLE handle;
		handle = HANDLE(wParam);
		NameLookup **walk;
		for(walk = &lookupList; *walk; walk = &((*walk)->nextLookup))
		{
			if((*walk)->lookupHandle == handle)
			{
				NameLookup *temp = *walk;
				struct hostent *hp = (struct hostent *) temp->hostEntStruct;

				if(error)
				{
					notifyEvent.state = ConnectedNotifyEvent::DNSFailed;
					notifyEvent.tag = temp->socket;
					::closesocket(temp->socket);
				}
				else
				{
					SOCKADDR_IN ipAddr;
					memcpy(&ipAddr.sin_addr.s_addr, hp->h_addr, sizeof(IN_ADDR));
					ipAddr.sin_port = temp->port;
					ipAddr.sin_family = AF_INET;

					notifyEvent.tag = temp->socket;

					WSAAsyncSelect(temp->socket, winsockWindow, WM_USER, FD_READ | FD_CONNECT | FD_CLOSE);
					bool wserr = ::connect(temp->socket, (PSOCKADDR) &ipAddr, sizeof(ipAddr)); // always errors out
					if (wserr && WSAGetLastError() == WSAEWOULDBLOCK)
						notifyEvent.state = ConnectedNotifyEvent::DNSResolved;
					else {
						Con::printf("Connect error: %d", WSAGetLastError());
						::closesocket(temp->socket);
						notifyEvent.state = ConnectedNotifyEvent::ConnectFailed;
					}
				}
				Game->postEvent(notifyEvent);

				*walk = temp->nextLookup;
				delete temp;
				break;
			}
		}
		break;
	default:
		return DefWindowProc( hWnd, message, wParam, lParam );
	}
	return 0;
}


static void InitNetWindow()
{
	WNDCLASS wc;
	dMemset(&wc, 0, sizeof(wc));

	wc.style         = 0;
	wc.lpfnWndProc   = WinsockProc;
	wc.cbClsExtra    = 0;
	wc.cbWndExtra    = 0;
	wc.hInstance     = winState.appInstance;
	wc.hIcon         = 0;
	wc.hCursor       = 0;
	wc.hbrBackground = 0;
	wc.lpszMenuName  = 0;
	wc.lpszClassName = dT("WinSockClass");
	RegisterClass( &wc );
	winsockWindow = CreateWindowEx(
		0,
		dT("WinSockClass"),
		dT(""),
		0,
		0, 0, 0, 0,
		NULL, NULL,
		winState.appInstance,
		NULL);
}

bool Net::init()
{
	WSADATA stWSAData;
	InitNetWindow();
	return !WSAStartup(0x0101, &stWSAData);
}

void Net::shutdown()
{
	while(lookupList)
	{
		NameLookup *temp = lookupList;
		lookupList = temp->nextLookup;
		WSACancelAsyncRequest ( temp->lookupHandle );
		delete temp;
	}
	DestroyWindow(winsockWindow);
	closePort();
	WSACleanup();
}

static void netToIPSocketAddress(const NetAddress *address, SOCKADDR_IN *sockAddr)
{
	dMemset(sockAddr, 0, sizeof(SOCKADDR_IN));
	sockAddr->sin_family = AF_INET;
	sockAddr->sin_port = htons(address->port);
	sockAddr->sin_addr.s_net = address->netNum[0];
	sockAddr->sin_addr.s_host = address->netNum[1];
	sockAddr->sin_addr.s_lh = address->netNum[2];
	sockAddr->sin_addr.s_impno = address->netNum[3];
}

static void IPSocketToNetAddress(const SOCKADDR_IN *sockAddr, NetAddress *address)
{
	address->type = NetAddress::IPAddress;
	address->port = htons(sockAddr->sin_port);
	address->netNum[0] = sockAddr->sin_addr.s_net;
	address->netNum[1] = sockAddr->sin_addr.s_host;
	address->netNum[2] = sockAddr->sin_addr.s_lh;
	address->netNum[3] = sockAddr->sin_addr.s_impno;
}

static void netToIPXSocketAddress(const NetAddress *address, SOCKADDR_IPX *sockAddr)
{
#if !defined(NO_IPX_SUPPORT)
	dMemset(sockAddr, 0, sizeof(SOCKADDR_IPX));
	sockAddr->sa_family = AF_INET;
	sockAddr->sa_socket = htons(address->port);
	sockAddr->sa_netnum[0] = address->netNum[0];
	sockAddr->sa_netnum[1] = address->netNum[1];
	sockAddr->sa_netnum[2] = address->netNum[2];
	sockAddr->sa_netnum[3] = address->netNum[3];
	sockAddr->sa_nodenum[0] = address->nodeNum[0];
	sockAddr->sa_nodenum[1] = address->nodeNum[1];
	sockAddr->sa_nodenum[2] = address->nodeNum[2];
	sockAddr->sa_nodenum[3] = address->nodeNum[3];
	sockAddr->sa_nodenum[4] = address->nodeNum[4];
	sockAddr->sa_nodenum[5] = address->nodeNum[5];
#endif
}

static void IPXSocketToNetAddress(const SOCKADDR_IPX *sockAddr, NetAddress *address)
{
#if !defined(NO_IPX_SUPPORT)
	address->type = NetAddress::IPXAddress;
	address->port = htons(sockAddr->sa_socket);
	address->netNum[0]  = sockAddr->sa_netnum[0] ;
	address->netNum[1]  = sockAddr->sa_netnum[1] ;
	address->netNum[2]  = sockAddr->sa_netnum[2] ;
	address->netNum[3]  = sockAddr->sa_netnum[3] ;
	address->nodeNum[0] = sockAddr->sa_nodenum[0];
	address->nodeNum[1] = sockAddr->sa_nodenum[1];
	address->nodeNum[2] = sockAddr->sa_nodenum[2];
	address->nodeNum[3] = sockAddr->sa_nodenum[3];
	address->nodeNum[4] = sockAddr->sa_nodenum[4];
	address->nodeNum[5] = sockAddr->sa_nodenum[5];
#endif
}

NetSocket Net::openListenPort(U16 port)
{
	if(Game->isJournalReading())
	{
		U32 ret;
		Game->journalRead(&ret);
		return NetSocket(ret);
	}
	NetSocket sock = openSocket();
	bind(sock, port);
	listen(sock, 4);
	setBlocking(sock, false);
	if(WSAAsyncSelect ( sock, winsockWindow, WM_USER, FD_ACCEPT ))
		Con::printf("Connect error: %d", WSAGetLastError());
	if(Game->isJournalWriting())
		Game->journalWrite(U32(sock));
	return sock;
}

NetSocket Net::openConnectTo(const char *addressString)
{
	if(!dStrnicmp(addressString, "ipx:", 4))
		return InvalidSocket;
	if(!dStrnicmp(addressString, "ip:", 3))
		addressString += 3;  // eat off the ip:
	char remoteAddr[256];
	dStrcpy(remoteAddr, addressString);

	char *portString = dStrchr(remoteAddr, ':');

	U16 port;
	if(portString)
	{
		*portString++ = 0;
		port = htons(dAtoi(portString));
	}
	else
		port = htons(defaultPort);

	if(!dStricmp(remoteAddr, "broadcast"))
		return InvalidSocket;

	if(Game->isJournalReading())
	{
		U32 ret;
		Game->journalRead(&ret);
		return NetSocket(ret);
	}
	NetSocket sock = openSocket();
	setBlocking(sock, false);

	SOCKADDR_IN ipAddr;

	ipAddr.sin_addr.s_addr = inet_addr(remoteAddr);

	if(ipAddr.sin_addr.s_addr != INADDR_NONE)
	{
		ipAddr.sin_port = port;
		ipAddr.sin_family = AF_INET;
		WSAAsyncSelect(sock, winsockWindow, WM_USER, FD_READ | FD_CONNECT | FD_CLOSE);
		if(::connect(sock, (PSOCKADDR) &ipAddr, sizeof(ipAddr) ) )
		{
			if(WSAGetLastError() != WSAEWOULDBLOCK)
			{
				Con::printf("Connect error: %d", WSAGetLastError());
				::closesocket(sock);
				sock = InvalidSocket;
			}
		}
	}
	else
	{
		NameLookup *lookup = new NameLookup;
		lookup->socket = sock;
		lookup->port = port;
		lookup->lookupHandle = WSAAsyncGetHostByName (winsockWindow, WM_USER + 1, remoteAddr, (char *) lookup->hostEntStruct, MAXGETHOSTSTRUCT );
		if(!lookup->lookupHandle)
		{
			delete lookup;
			::closesocket(sock);
			sock = InvalidSocket;
		}
		else
		{
			lookup->nextLookup = lookupList;
			lookupList = lookup;
		}
	}
	if(Game->isJournalWriting())
		Game->journalWrite(U32(sock));
	return sock;
}

void Net::closeConnectTo(NetSocket sock)
{
	if(Game->isJournalReading())
		return;

	for(NameLookup **walk = &lookupList; *walk; walk = &((*walk)->nextLookup) )
	{
		NameLookup *lookup = *walk;
		if(lookup->socket == sock)
		{
			WSACancelAsyncRequest ( lookup->lookupHandle );
			closesocket(lookup->socket);
			*walk = lookup->nextLookup;
			delete lookup;
			return;
		}
	}
	closesocket(sock);
}

Net::Error Net::sendtoSocket(NetSocket socket, const U8 *buffer, S32 bufferSize)
{
	if(Game->isJournalReading())
	{
		U32 e;
		Game->journalRead(&e);

		return (Net::Error) e;
	}
	Net::Error e = send(socket, buffer, bufferSize);
	if(Game->isJournalWriting())
		Game->journalWrite(U32(e));
	return e;
}

bool Net::openPort(S32 port)
{
	if(udpSocket != INVALID_SOCKET)
		closesocket(udpSocket);
	if(ipxSocket != INVALID_SOCKET)
		closesocket(ipxSocket);

	udpSocket = socket(AF_INET, SOCK_DGRAM, 0);

#if !defined(NO_IPX_SUPPORT)
	ipxSocket = socket(AF_IPX, SOCK_DGRAM, NSPROTO_IPX);
#else
	ipxSocket = INVALID_SOCKET;
#endif

	if(udpSocket != INVALID_SOCKET)
	{
		Net::Error error;
		error = bind(udpSocket, port);
		if(error == NoError)
			error = setBufferSize(udpSocket, 32768);
		if(error == NoError)
			error = setBroadcast(udpSocket, true);
		if(error == NoError)
			error = setBlocking(udpSocket, false);
		if(error == NoError)
			Con::printf("UDP initialized on port %d", port);
		else
		{
			closesocket(udpSocket);
			udpSocket = INVALID_SOCKET;
			Con::printf("Unable to initialize UDP - error %d", error);
		}
	}

#if !defined(NO_IPX_SUPPORT)
	if(ipxSocket != INVALID_SOCKET)
	{
		Net::Error error = NoError;
		SOCKADDR_IPX ipxAddress;
		memset((char *)&ipxAddress, 0, sizeof(ipxAddress));
		ipxAddress.sa_family = AF_IPX;
		ipxAddress.sa_socket = htons(port);
		S32 err = ::bind(ipxSocket, (PSOCKADDR) &ipxAddress, sizeof(ipxAddress));
		if(err)
			error = getLastError();
		if(error == NoError)
			error = setBufferSize(ipxSocket, 32768);
		if(error == NoError)
			error = setBroadcast(ipxSocket, true);
		if(error == NoError)
			error = setBlocking(ipxSocket, false);
		if(error == NoError)
			Con::printf("IPX initialized on port %d", port);
		else
		{
			closesocket(ipxSocket);
			ipxSocket = INVALID_SOCKET;
			Con::printf("Unable to initialize IPX - error %d", error);
		}
	}
#endif
	netPort = port;
	return ipxSocket != INVALID_SOCKET || udpSocket != INVALID_SOCKET;
}

void Net::closePort()
{
	if(ipxSocket != INVALID_SOCKET)
		closesocket(ipxSocket);
	if(udpSocket != INVALID_SOCKET)
		closesocket(udpSocket);
}

Net::Error Net::sendto(const NetAddress *address, const U8 *buffer, S32 bufferSize)
{
	if(Game->isJournalReading())
		return NoError;

	if(address->type == NetAddress::IPXAddress)
	{
		SOCKADDR_IPX ipxAddr;
		netToIPXSocketAddress(address, &ipxAddr);
		if(::sendto(ipxSocket, (const char*)buffer, bufferSize, 0,
			(PSOCKADDR) &ipxAddr, sizeof(SOCKADDR_IPX)) == SOCKET_ERROR)
			return getLastError();
		else
			return NoError;
	}
	else
	{
		SOCKADDR_IN ipAddr;
		netToIPSocketAddress(address, &ipAddr);
		if(::sendto(udpSocket, (const char*)buffer, bufferSize, 0,
			(PSOCKADDR) &ipAddr, sizeof(SOCKADDR_IN)) == SOCKET_ERROR)
			return getLastError();
		else
			return NoError;
	}
}

void Net::process()
{
	SOCKADDR sa;

	PacketReceiveEvent receiveEvent;
	for(;;)
	{
		S32 addrLen = sizeof(sa);
		S32 bytesRead = SOCKET_ERROR;
		if(udpSocket != INVALID_SOCKET)
			bytesRead = recvfrom(udpSocket, (char *) receiveEvent.data, MaxPacketDataSize, 0, &sa, &addrLen);
		if(bytesRead == SOCKET_ERROR && ipxSocket != INVALID_SOCKET)
		{
			addrLen = sizeof(sa);
			bytesRead = recvfrom(ipxSocket, (char *) receiveEvent.data, MaxPacketDataSize, 0, &sa, &addrLen);
		}

		if(bytesRead == SOCKET_ERROR)
			break;

		if(sa.sa_family == AF_INET)
			IPSocketToNetAddress((SOCKADDR_IN *) &sa, &receiveEvent.sourceAddress);
		else if(sa.sa_family == AF_IPX)
			IPXSocketToNetAddress((SOCKADDR_IPX *) &sa, &receiveEvent.sourceAddress);
		else
			continue;

		NetAddress &na = receiveEvent.sourceAddress;
		if(na.type == NetAddress::IPAddress &&
			na.netNum[0] == 127 &&
			na.netNum[1] == 0 &&
			na.netNum[2] == 0 &&
			na.netNum[3] == 1 &&
			na.port == netPort)
			continue;
		if(bytesRead <= 0)
			continue;
		receiveEvent.size = PacketReceiveEventHeaderSize + bytesRead;
		Game->postEvent(receiveEvent);
	}
}

NetSocket Net::openSocket()
{
	SOCKET retSocket;
	retSocket = socket(AF_INET, SOCK_STREAM, 0);

	if(retSocket == INVALID_SOCKET)
		return InvalidSocket;
	else
		return retSocket;
}

Net::Error Net::closeSocket(NetSocket socket)
{
	if(socket != InvalidSocket)
	{
		if(!closesocket(socket))
			return NoError;
		else
			return getLastError();
	}
	else
		return NotASocket;
}

Net::Error Net::connect(NetSocket socket, const NetAddress *address)
{
	if(address->type != NetAddress::IPAddress)
		return WrongProtocolType;
	SOCKADDR_IN socketAddress;
	netToIPSocketAddress(address, &socketAddress);
	if(!::connect(socket, (PSOCKADDR) &socketAddress, sizeof(socketAddress)))
		return NoError;
	return getLastError();
}

Net::Error Net::listen(NetSocket socket, S32 backlog)
{
	if(!::listen(socket, backlog))
		return NoError;
	return getLastError();
}

NetSocket Net::accept(NetSocket acceptSocket, NetAddress *remoteAddress)
{
	SOCKADDR_IN socketAddress;
	S32 addrLen = sizeof(socketAddress);

	SOCKET retVal = ::accept(acceptSocket, (PSOCKADDR) &socketAddress, &addrLen);
	if(retVal != INVALID_SOCKET)
	{
		IPSocketToNetAddress(&socketAddress, remoteAddress);
		return retVal;
	}
	return InvalidSocket;
}

Net::Error Net::bind(NetSocket socket, U16 port)
{
	S32 error;

	SOCKADDR_IN socketAddress;
	dMemset((char *)&socketAddress, 0, sizeof(socketAddress));
	socketAddress.sin_family = AF_INET;
	// It's entirely possible that there are two NIC cards.
	// We let the user specify which one the server runs on.

	// thanks to [TPG]P1aGu3 for the name
	const char* serverIP = Con::getVariable( "Pref::Net::BindAddress" );
	// serverIP is guaranteed to be non-0.
	AssertFatal( serverIP, "serverIP is NULL!" );

	if( serverIP[0] != '\0' ) {
		// we're not empty
		socketAddress.sin_addr.s_addr = inet_addr( serverIP );

		if( socketAddress.sin_addr.s_addr != INADDR_NONE ) {
			Con::printf( "Binding server port to %s", serverIP );
		} else {
			Con::warnf( ConsoleLogEntry::General,
				"inet_addr() failed for %s while binding!",
				serverIP );
			socketAddress.sin_addr.s_addr = INADDR_ANY;
		}

	} else {
		Con::printf( "Binding server port to default IP" );
		socketAddress.sin_addr.s_addr = INADDR_ANY;
	}

	socketAddress.sin_port = htons(port);
	error = ::bind(socket, (PSOCKADDR) &socketAddress, sizeof(socketAddress));

	if(!error)
		return NoError;
	return getLastError();
}

Net::Error Net::setBufferSize(NetSocket socket, S32 bufferSize)
{
	S32 error;
	error = setsockopt(socket, SOL_SOCKET, SO_RCVBUF, (char *) &bufferSize, sizeof(bufferSize));
	if(!error)
		error = setsockopt(socket, SOL_SOCKET, SO_SNDBUF, (char *) &bufferSize, sizeof(bufferSize));
	if(!error)
		return NoError;
	return getLastError();
}

Net::Error Net::setBroadcast(NetSocket socket, bool broadcast)
{
	S32 bc = broadcast;
	S32 error = setsockopt(socket, SOL_SOCKET, SO_BROADCAST, (char*)&bc, sizeof(bc));
	if(!error)
		return NoError;
	return getLastError();
}

Net::Error Net::setBlocking(NetSocket socket, bool blockingIO)
{
	DWORD notblock = !blockingIO;
	S32 error = ioctlsocket(socket, FIONBIO, &notblock);
	if(!error)
		return NoError;
	return getLastError();
}

Net::Error Net::send(NetSocket socket, const U8 *buffer, S32 bufferSize)
{
	S32 error = ::send(socket, (const char*)buffer, bufferSize, 0);
	if(!error)
		return NoError;
	return getLastError();
}

Net::Error Net::recv(NetSocket socket, U8 *buffer, S32 bufferSize, S32 *bytesRead)
{
	*bytesRead = ::recv(socket, (char*)buffer, bufferSize, 0);
	if(*bytesRead == SOCKET_ERROR)
		return getLastError();
	return NoError;
}

bool Net::compareAddresses(const NetAddress *a1, const NetAddress *a2)
{
	if((a1->type != a2->type)  ||
		(*((U32 *)a1->netNum) != *((U32 *)a2->netNum)) ||
		(a1->port != a2->port))
		return false;

	if(a1->type == NetAddress::IPAddress)
		return true;
	for(S32 i = 0; i < 6; i++)
		if(a1->nodeNum[i] != a2->nodeNum[i])
			return false;
	return true;
}

bool Net::stringToAddress(const char *addressString, NetAddress *address)
{
	if(dStrnicmp(addressString, "ipx:", 4))
	{
		// assume IP if it doesn't have ipx: at the front.

		if(!dStrnicmp(addressString, "ip:", 3))
			addressString += 3;  // eat off the ip:

		SOCKADDR_IN ipAddr;
		char remoteAddr[256];
		if(strlen(addressString) > 255)
			return false;

		dStrcpy(remoteAddr, addressString);

		char *portString = dStrchr(remoteAddr, ':');
		if(portString)
			*portString++ = 0;

		struct hostent *hp;

		if(!dStricmp(remoteAddr, "broadcast"))
			ipAddr.sin_addr.s_addr = htonl(INADDR_BROADCAST);
		else
		{
			ipAddr.sin_addr.s_addr = inet_addr(remoteAddr);
			if(ipAddr.sin_addr.s_addr == INADDR_NONE)
			{
				if((hp = gethostbyname(remoteAddr)) == NULL)
					return false;
				else
					memcpy(&ipAddr.sin_addr.s_addr, hp->h_addr, sizeof(IN_ADDR));
			}
		}
		if(portString)
			ipAddr.sin_port = htons(dAtoi(portString));
		else
			ipAddr.sin_port = htons(defaultPort);
		ipAddr.sin_family = AF_INET;
		IPSocketToNetAddress(&ipAddr, address);
		return true;
	}
	else
	{
		S32 i;
		S32 port;

		address->type = NetAddress::IPXAddress;
		for(i = 0; i < 6; i++)
			address->nodeNum[i] = 0xFF;

		// it's an IPX string
		addressString += 4;
		if(!dStricmp(addressString, "broadcast"))
		{
			address->port = defaultPort;
			return true;
		}
		else if(sscanf(addressString, "broadcast:%d", &port) == 1)
		{
			address->port = port;
			return true;
		}
		else
		{
			S32 nodeNum[6];
			S32 netNum[4];
			S32 count = dSscanf(addressString, "%2x%2x%2x%2x:%2x%2x%2x%2x%2x%2x:%d",
				&netNum[0], &netNum[1], &netNum[2], &netNum[3],
				&nodeNum[0], &nodeNum[1], &nodeNum[2], &nodeNum[3], &nodeNum[4], &nodeNum[5],
				&port);

			if(count == 10)
			{
				port = defaultPort;
				count++;
			}
			if(count != 11)
				return false;

			for(i = 0; i < 6; i++)
				address->nodeNum[i] = nodeNum[i];
			for(i = 0; i < 4; i++)
				address->netNum[i] = netNum[i];
			address->port = port;
			return true;
		}
	}
}

void Net::addressToString(const NetAddress *address, char addressString[256])
{
	if(address->type == NetAddress::IPAddress)
	{
		SOCKADDR_IN ipAddr;
		netToIPSocketAddress(address, &ipAddr);

		if(ipAddr.sin_addr.s_addr == htonl(INADDR_BROADCAST))
			dSprintf(addressString, 256, "IP:Broadcast:%d", ntohs(ipAddr.sin_port));
		else
			dSprintf(addressString, 256, "IP:%d.%d.%d.%d:%d", ipAddr.sin_addr.s_net,
			ipAddr.sin_addr.s_host, ipAddr.sin_addr.s_lh,
			ipAddr.sin_addr.s_impno, ntohs(ipAddr.sin_port));
	}
	else
	{
		dSprintf(addressString, 256, "IPX:%.2X%.2X%.2X%.2X:%.2X%.2X%.2X%.2X%.2X%.2X:%d",
			address->netNum[0], address->netNum[1], address->netNum[2], address->netNum[3],
			address->nodeNum[0], address->nodeNum[1], address->nodeNum[2], address->nodeNum[3], address->nodeNum[4], address->nodeNum[5],
			address->port);
	}
}

Net::Error getLastError()
{
	S32 err = WSAGetLastError();
	switch(err)
	{
	case WSAEWOULDBLOCK:
		return Net::WouldBlock;
	default:
		return Net::UnknownError;
	}
}
*/